from support.ui.console import Log
from threading import RLock
from concurrent.futures import ThreadPoolExecutor, as_completed, ALL_COMPLETED, wait
from typing import (
        IO,
        TYPE_CHECKING,
        Any,
        Callable,
        Dict,
        Iterable,
        List,
        Mapping,
        NamedTuple,
        Optional,
        TextIO,
        Tuple,
        Type,
        Union,
        cast,
    )
class Task:
    TAG = "Task"
    def __init__(self, maxqueue=10, *, dashboard=None):
        self.maxqueue = maxqueue
        self.threadPool = ThreadPoolExecutor(maxqueue)
        self._lock = RLock()
        self.dashboard = dashboard
        self.idleQueue = []
        self.runningQueue = []
        self.boardshown = False

    def __enter__(self):
        if(self.dashboard is not None and not self.boardshown):
            self.dashboard.show()
            #self.threadPool.submit(self.dashboard.show)
            self.boardshown = True
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        if(self.dashboard is not None and self.boardshown):
            Log.i("Live is out!", exc_type, exc_value)
            self.dashboard.hiden()

    def updateProgress(self, *, total=None, advance=None):
        if(self.dashboard is not None):
            self.dashboard.updateMainProgress(total=total, advance=advance)
            self.dashboard.update()

    def updateProgressProcess(self, progressid, advance):
        if(self.dashboard is not None):
            self.dashboard.updateJobsProgress(progressid, advance=advance)
            self.dashboard.update()

    def execJobs(self, force=False):
        self._lock.acquire()
        #if(force or len(self.idleQueue) >= self.maxqueue):
        for task in self.idleQueue:
            progressid = None
            if(self.dashboard is not None):
                progressid = self.dashboard.startProgress(task['description'], task['total'])
                Log.d(Task.TAG, "get a new progress, id:", progressid)
            self.runningQueue.append(self.threadPool.submit(task['func'], *task['args'], progressid))
        self.idleQueue.clear()
        while(len(self.runningQueue) >= self.maxqueue):
            Log.i(Task.TAG, "waiting for all running thread completed", len(self.runningQueue))
            for thread in as_completed(self.runningQueue):
                self.updateProgress(advance=1)
                self.runningQueue.remove(thread)
                break
        if(force):
            for thread in as_completed(self.runningQueue):
                Log.i(Task.TAG, thread)
                self.updateProgress(advance=1)
            self.runningQueue.clear()
        self._lock.release()

    def submitJobsTask(self, func: Optional[Callable[[any], any]], args:Optional[any], description:str=None, total=0):
        Log.d(Task.TAG, len(self.idleQueue), self.idleQueue)
        self._lock.acquire()
        self.idleQueue.append({'func':func, 'args':args, 'description':description, 'total':total})
        self._lock.release()
        self.execJobs()
    
    def waitAllFinished(self, timeout=1):
        self.execJobs(True)